/*
 * Copyright (C) 2005 - 2013 MaNGOS <http://www.getmangos.com/>
 *
 * Copyright (C) 2008 - 2013 Trinity <http://www.trinitycore.org/>
 *
 * Copyright (C) 2006 - 2013 ScriptDev2 <http://www.scriptdev2.com/>
 *
 * Copyright (C) 2010 - 2013 ProjectSkyfire <http://www.projectskyfire.org/>
 *
 * Copyright (C) 2011 - 2013 ArkCORE <http://www.arkania.net/>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

//TODO: Harpoon event is automated needs to be checked
/* ScriptData
 SDName: Razorscale
 SDAuthor: PrinceCreed
 SD%Complete: 100
 EndScriptData */

#include "ScriptPCH.h"
#include "ulduar.h"

enum Says {
    SAY_GREET = -1603260,
    SAY_GROUND_PHASE = -1603261,
    SAY_AGGRO_1 = -1603262,
    SAY_AGGRO_2 = -1603263,
    SAY_AGGRO_3 = -1603264,
    SAY_TURRETS = -1603265,
    EMOTE_HARPOON = -1603266,
    EMOTE_BREATH = -1603267,
    EMOTE_PERMA = -1603268,
};

#define GOSSIP_ITEM_1 "Activate Harpoones!"
#define DATA_QUICK_SHAVE                         29192921 // 2919, 2921 are achievement IDs

enum Spells {
    SPELL_FLAMEBUFFET = 64016,
    SPELL_FIREBALL = 62796,
    SPELL_FLAME_GROUND = 64709,
    SPELL_WINGBUFFET = 62666,
    SPELL_FLAMEBREATH = 63317,
    SPELL_FUSEARMOR = 64771,
    SPELL_DEVOURING_FLAME = 63236,
    SPELL_HARPOON = 54933,
    SPELL_FLAMED = 62696,
    SPELL_STUN = 9032,
    SPELL_BERSERK = 47008
};

const Position PosHarpoon[4] = { { 594.317f, -136.953f, 391.517f, 4.544f }, {
        577.449f, -136.953f, 391.517f, 4.877f }, { 607.726f, -146.857f,
        391.517f, 4.041f }, { 561.449f, -146.857f, 391.517f, 5.426f } };

const Position PosEngSpawn = { 591.951f, -95.968f, 391.517f, 0 };

const Position PosEngRepair[4] = { { 590.442f, -130.550f, 391.517f, 4.789f }, {
        574.850f, -133.687f, 391.517f, 4.252f }, { 606.567f, -143.369f,
        391.517f, 4.434f }, { 560.609f, -142.967f, 391.517f, 5.074f } };

const Position PosDefSpawn[4] = { { 600.75f, -104.850f, 391.517f, 0 }, {
        596.38f, -110.262f, 391.517f, 0 }, { 566.47f, -103.633f, 391.517f, 0 },
        { 570.41f, -108.791f, 391.517f, 0 } };

const Position PosDefCombat[4] = { { 614.975f, -155.138f, 391.517f, 4.154f }, {
        609.814f, -204.968f, 391.517f, 5.385f }, { 563.531f, -201.557f,
        391.517f, 4.108f }, { 560.231f, -153.677f, 391.517f, 5.403f } };

const Position RazorFlight = { 588.050f, -251.191f, 470.536f, 1.605f };
const Position RazorGround = { 586.966f, -175.534f, 391.517f, 1.692f };

enum Mobs {
    RAZORSCALE = 33186, // ?? why not use instance?
    NPC_DARK_RUNE_GUARDIAN = 33388,
    NPC_DARK_RUNE_SENTINEL = 33846,
    NPC_DARK_RUNE_WATCHER = 33453,
    MOLE_MACHINE_TRIGGER = 33245,
    NPC_COMMANDER = 33210,
    NPC_ENGINEER = 33287,
    NPC_DEFENDER = 33816,
    NPC_HARPOON = 33184,
    GOB_MOLE_MACHINE = 194316
};

enum DarkRuneSpells {
    // Dark Rune Watcher
    SPELL_CHAIN_LIGHTNING = 64758,
    SPELL_LIGHTNING_BOLT = 63809,

    // Dark Rune Guardian
    SPELL_STORMSTRIKE = 64757,

    // Dark Rune Sentinel
    SPELL_BATTLE_SHOUT = 46763,
    SPELL_HEROIC_STRIKE = 45026,
    SPELL_WHIRLWIND = 63807,
};

#define ACHIEVEMENT_QUICK_SHAVE     RAID_MODE(2919, 2921)

#define ACTION_EVENT_START          1
#define ACTION_GROUND_PHASE         2

enum Phases {
    PHASE_NULL, PHASE_PERMAGROUND, PHASE_GROUND, PHASE_FLIGHT
};

enum Events {
    EVENT_NONE,
    EVENT_BERSERK,
    EVENT_BREATH,
    EVENT_BUFFET,
    EVENT_HARPOON,
    EVENT_FIREBALL,
    EVENT_FLIGHT,
    EVENT_DEVOURING,
    EVENT_FLAME,
    EVENT_LAND,
    EVENT_GROUND,
    EVENT_FUSE,
    EVENT_SUMMON
};

class boss_razorscale: public CreatureScript {
public:
    boss_razorscale() :
            CreatureScript("boss_razorscale") {
    }

    CreatureAI* GetAI(Creature* pCreature) const {
        return new boss_razorscaleAI(pCreature);
    }

    struct boss_razorscaleAI: public BossAI {
        boss_razorscaleAI(Creature *pCreature) :
                BossAI(pCreature, TYPE_RAZORSCALE), phase(PHASE_NULL) {
            // Do not let Razorscale be affected by Battle Shout buff
            me->ApplySpellImmune(0, IMMUNITY_ID, (SPELL_BATTLE_SHOUT), true);
            me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK,
                    true);
            me->ApplySpellImmune(0, IMMUNITY_ID, 49560, true); // Death Grip
        }

        Phases phase;

        uint32 EnrageTimer;
        uint32 FlyCount;

        Creature* Harpoon[4];
        bool PermaGround;
        bool Enraged;

        void Reset() {
            _Reset();
            me->SetFlying(true);
            me->SetFlag(UNIT_FIELD_FLAGS,
                    UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
            me->SetReactState(REACT_PASSIVE);
            PermaGround = false;
        }

        void EnterCombat(Unit* /*who*/) {
            _EnterCombat();
            for (uint8 n = 0; n < RAID_MODE(2, 4); ++n)
                Harpoon[n] = me->SummonCreature(NPC_HARPOON, PosHarpoon[n],
                        TEMPSUMMON_CORPSE_TIMED_DESPAWN, 0);
            me->SetSpeed(MOVE_FLIGHT, 3.0f, true);
            me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
            me->SetReactState(REACT_PASSIVE);
            phase = PHASE_GROUND;
            events.SetPhase(PHASE_GROUND);
            FlyCount = 0;
            EnrageTimer = 15 * 60 * 1000; // Enrage in 15 min
            Enraged = false;
            events.ScheduleEvent(EVENT_FLIGHT, 0, 0, PHASE_GROUND);
        }

        void JustDied(Unit* /*Killer*/) {
            _JustDied();

            if (instance) {
                // A Quick Shave
                if (FlyCount <= 2)
                    instance->DoCompleteAchievement(ACHIEVEMENT_QUICK_SHAVE);
            }
        }

        void UpdateAI(const uint32 diff) {
            if (!UpdateVictim())
                return;

            if (me->getVictim()
                    && !me->getVictim()->GetCharmerOrOwnerPlayerOrPlayerItself())
                me->Kill(me->getVictim());

            events.Update(diff);

            if (HealthBelowPct(50) && !PermaGround)
                EnterPermaGround();

            if (EnrageTimer <= diff && !Enraged) {
                DoCast(me, SPELL_BERSERK);
                Enraged = true;
            } else
                EnrageTimer -= diff;

            if (phase == PHASE_GROUND) {
                while (uint32 eventId = events.ExecuteEvent()) {
                    switch (eventId) {
                    case EVENT_FLIGHT:
                        phase = PHASE_FLIGHT;
                        events.SetPhase(PHASE_FLIGHT);
                        me->SetFlying(true);
                        me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
                        me->SetReactState(REACT_PASSIVE);
                        me->AttackStop();
                        me->RemoveAllAuras();
                        me->GetMotionMaster()->MovePoint(0, RazorFlight);
                        events.ScheduleEvent(EVENT_FIREBALL, 7000, 0,
                                PHASE_FLIGHT);
                        events.ScheduleEvent(EVENT_DEVOURING, 10000, 0,
                                PHASE_FLIGHT);
                        events.ScheduleEvent(EVENT_SUMMON, 5000, 0,
                                PHASE_FLIGHT);
                        events.ScheduleEvent(EVENT_GROUND, 75000, 0,
                                PHASE_FLIGHT);
                        ++FlyCount;
                        return;
                    case EVENT_LAND:
                        me->SetFlying(false);
                        me->NearTeleportTo(586.966f, -175.534f, 391.517f,
                                1.692f);
                        DoCast(me, SPELL_STUN, true);
                        me->RemoveFlag(UNIT_FIELD_FLAGS,
                                UNIT_FLAG_NON_ATTACKABLE);
                        if (Creature *pCommander = me->GetCreature(*me, instance->GetData64(DATA_EXP_COMMANDER)))
                            pCommander->AI()->DoAction(ACTION_GROUND_PHASE);
                        events.ScheduleEvent(EVENT_HARPOON, 0, 0, PHASE_GROUND);
                        events.ScheduleEvent(EVENT_BREATH, 30000, 0,
                                PHASE_GROUND);
                        events.ScheduleEvent(EVENT_BUFFET, 33000, 0,
                                PHASE_GROUND);
                        events.ScheduleEvent(EVENT_FLIGHT, 35000, 0,
                                PHASE_GROUND);
                        return;
                    case EVENT_HARPOON:
                        for (uint8 n = 0; n < RAID_MODE(2, 4); ++n)
                            if (Harpoon[n])
                                Harpoon[n]->CastSpell(me, SPELL_HARPOON, true);
                        events.ScheduleEvent(EVENT_HARPOON, 1500, 0,
                                PHASE_GROUND);
                        return;
                    case EVENT_BREATH:
                        me->MonsterTextEmote(EMOTE_BREATH, 0, true);
                        DoCastAOE(SPELL_FLAMEBREATH);
                        events.CancelEvent(EVENT_HARPOON);
                        events.CancelEvent(EVENT_BREATH);
                        return;
                    case EVENT_BUFFET:
                        DoCastAOE(SPELL_WINGBUFFET);
                        for (uint8 n = 0; n < RAID_MODE(2, 4); ++n)
                            if (Harpoon[n])
                                Harpoon[n]->CastSpell(Harpoon[n], SPELL_FLAMED,
                                        true);
                        events.CancelEvent(EVENT_BUFFET);
                        return;
                    }
                }
            }
            if (phase == PHASE_PERMAGROUND) {
                while (uint32 eventId = events.ExecuteEvent()) {
                    switch (eventId) {
                    case EVENT_FLAME:
                        DoCastAOE(SPELL_FLAMEBUFFET);
                        events.ScheduleEvent(EVENT_FLAME, 10000, 0,
                                PHASE_PERMAGROUND);
                        return;
                    case EVENT_BREATH:
                        me->MonsterTextEmote(EMOTE_BREATH, 0, true);
                        DoCastVictim(SPELL_FLAMEBREATH);
                        events.ScheduleEvent(EVENT_BREATH, 20000, 0,
                                PHASE_PERMAGROUND);
                        return;
                    case EVENT_FIREBALL:
                        if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 200, true))
                            DoCast(pTarget, SPELL_FIREBALL);
                        events.ScheduleEvent(EVENT_FIREBALL, 3000, 0,
                                PHASE_PERMAGROUND);
                        return;
                    case EVENT_DEVOURING:
                        if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 200, true))
                            DoCast(pTarget, SPELL_DEVOURING_FLAME);
                        events.ScheduleEvent(EVENT_DEVOURING, 10000, 0,
                                PHASE_PERMAGROUND);
                        return;
                    case EVENT_BUFFET:
                        DoCastAOE(SPELL_WINGBUFFET);
                        events.CancelEvent(EVENT_BUFFET);
                        return;
                    case EVENT_FUSE:
                        DoCastVictim(SPELL_FUSEARMOR);
                        events.ScheduleEvent(EVENT_FUSE, 10000, 0,
                                PHASE_PERMAGROUND);
                        return;
                    }
                }

                DoMeleeAttackIfReady();
            } else {
                if (uint32 eventId = events.ExecuteEvent()) {
                    switch (eventId) {
                    case EVENT_GROUND:
                        phase = PHASE_GROUND;
                        events.SetPhase(PHASE_GROUND);
                        if (Harpoon[0])
                            Harpoon[0]->MonsterTextEmote(EMOTE_HARPOON, 0,
                                    true);
                        me->GetMotionMaster()->MovePoint(0, RazorGround);
                        events.ScheduleEvent(EVENT_LAND, 5500, 0, PHASE_GROUND);
                        return;
                    case EVENT_FIREBALL:
                        if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 200, true))
                            DoCast(pTarget, SPELL_FIREBALL);
                        events.ScheduleEvent(EVENT_FIREBALL, 3000, 0,
                                PHASE_FLIGHT);
                        return;
                    case EVENT_DEVOURING:
                        if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 200, true))
                            DoCast(pTarget, SPELL_DEVOURING_FLAME);
                        events.ScheduleEvent(EVENT_DEVOURING, 10000, 0,
                                PHASE_FLIGHT);
                        return;
                    case EVENT_SUMMON:
                        SummonAdds();
                        events.ScheduleEvent(EVENT_SUMMON, 45000, 0,
                                PHASE_FLIGHT);
                        return;
                    }
                }
            }
        }

        void EnterPermaGround() {
            me->MonsterTextEmote(EMOTE_PERMA, 0, true);
            phase = PHASE_PERMAGROUND;
            events.SetPhase(PHASE_PERMAGROUND);
            me->SetFlying(false);
            me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
            me->SetReactState(REACT_AGGRESSIVE);
            me->RemoveAurasDueToSpell(SPELL_STUN);
            me->SetSpeed(MOVE_FLIGHT, 1.0f, true);
            PermaGround = true;
            DoCastAOE(SPELL_FLAMEBREATH);
            events.ScheduleEvent(EVENT_FLAME, 15000, 0, PHASE_PERMAGROUND);
            events.RescheduleEvent(EVENT_DEVOURING, 15000, 0,
                    PHASE_PERMAGROUND);
            events.RescheduleEvent(EVENT_BREATH, 20000, 0, PHASE_PERMAGROUND);
            events.RescheduleEvent(EVENT_FIREBALL, 3000, 0, PHASE_PERMAGROUND);
            events.RescheduleEvent(EVENT_DEVOURING, 6000, 0, PHASE_PERMAGROUND);
            events.RescheduleEvent(EVENT_BUFFET, 2500, 0, PHASE_PERMAGROUND);
            events.RescheduleEvent(EVENT_FUSE, 5000, 0, PHASE_PERMAGROUND);
        }

        void SummonAdds() {
            // Adds will come in waves from mole machines. One mole can spawn a Dark Rune Watcher
            // with 1-2 Guardians, or a lone Sentinel. Up to 4 mole machines can spawn adds at any given time.
            uint8 random = urand(1, 4);
            for (uint8 i = 0; i < random; ++i) {
                float x = float(irand(540, 640)); // Safe range is between 500 and 650
                float y = float(irand(-230, -195)); // Safe range is between -235 and -145
                float z = 391.5f; // Ground level
                me->SummonCreature(MOLE_MACHINE_TRIGGER, x, y, z, 0,
                        TEMPSUMMON_TIMED_DESPAWN, 10000);
            }
        }

        void DoAction(const int32 action) {
            switch (action) {
            case ACTION_EVENT_START:
                me->RemoveFlag(UNIT_FIELD_FLAGS,
                        UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
                me->SetReactState(REACT_AGGRESSIVE);
                DoZoneInCombat();
                break;
            }
        }
    };
};

/*====================================================================================
 ====================================================================================*/

class npc_expedition_commander: public CreatureScript {
public:
    npc_expedition_commander() :
            CreatureScript("npc_expedition_commander") {
    }

    bool OnGossipSelect(Player* pPlayer, Creature* pCreature,
            uint32 /*uiSender*/, uint32 uiAction) {
        pPlayer->PlayerTalkClass->ClearMenus();
        switch (uiAction) {
        case GOSSIP_ACTION_INFO_DEF:
            if (pPlayer)
                pPlayer->CLOSE_GOSSIP_MENU();
            CAST_AI(npc_expedition_commanderAI, (pCreature->AI()))->uiPhase = 1;
            break;
        }
        return true;
    }

    bool OnGossipHello(Player* pPlayer, Creature* pCreature) {
        InstanceScript* pInstance = pCreature->GetInstanceScript();
        if (pInstance && pInstance->GetBossState(TYPE_RAZORSCALE) == NOT_STARTED
                && pPlayer) {
            pPlayer->PrepareGossipMenu(pCreature);

            pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF);
            pPlayer->SEND_GOSSIP_MENU(13853, pCreature->GetGUID());
        } else
            pPlayer->SEND_GOSSIP_MENU(13910, pCreature->GetGUID());

        return true;
    }

    CreatureAI* GetAI(Creature* pCreature) const {
        return new npc_expedition_commanderAI(pCreature);
    }

    struct npc_expedition_commanderAI: public ScriptedAI {
        npc_expedition_commanderAI(Creature* pCreature) :
                ScriptedAI(pCreature), summons(me) {
            pInstance = pCreature->GetInstanceScript();
            greet = false;
        }

        InstanceScript* pInstance;
        SummonList summons;

        bool greet;
        uint32 uiTimer;
        uint8 uiPhase;
        Creature* engineer[4];
        Creature* defender[4];

        void Reset() {
            uiTimer = 0;
            uiPhase = 0;
            greet = false;
        }

        void MoveInLineOfSight(Unit *who) {
            if (!greet && me->IsWithinDistInMap(who, 10.0f)
                    && who->GetTypeId() == TYPEID_PLAYER) {
                DoScriptText(SAY_GREET, me);
                greet = true;
            }
        }

        void JustSummoned(Creature *summon) {
            summons.Summon(summon);
        }

        void DoAction(const int32 action) {
            switch (action) {
            case ACTION_GROUND_PHASE:
                DoScriptText(SAY_GROUND_PHASE, me);
                break;
            }
        }

        void UpdateAI(const uint32 uiDiff) {
            ScriptedAI::UpdateAI(uiDiff);
            if (uiTimer <= uiDiff) {
                switch (uiPhase) {
                case 1:
                    pInstance->SetBossState(TYPE_RAZORSCALE, IN_PROGRESS);
                    summons.DespawnAll();
                    uiTimer = 1000;
                    uiPhase = 2;
                    break;
                case 2:
                    for (uint8 n = 0; n < RAID_MODE(2, 4); ++n) {
                        engineer[n] = me->SummonCreature(NPC_ENGINEER,
                                PosEngSpawn, TEMPSUMMON_CORPSE_TIMED_DESPAWN,
                                3000);
                        engineer[n]->RemoveUnitMovementFlag(
                                MOVEMENTFLAG_WALKING);
                        engineer[n]->SetSpeed(MOVE_RUN, 0.5f);
                        engineer[n]->SetHomePosition(PosEngRepair[n]);
                        engineer[n]->GetMotionMaster()->MoveTargetedHome();
                    }
                    engineer[0]->MonsterYell(SAY_AGGRO_3, LANG_UNIVERSAL, 0);
                    uiPhase = 3;
                    uiTimer = 14000;
                    break;
                case 3:
                    for (uint8 n = 0; n < 4; ++n) {
                        defender[n] = me->SummonCreature(NPC_DEFENDER,
                                PosDefSpawn[n], TEMPSUMMON_CORPSE_TIMED_DESPAWN,
                                3000);
                        defender[n]->RemoveUnitMovementFlag(
                                MOVEMENTFLAG_WALKING);
                        defender[n]->SetHomePosition(PosDefCombat[n]);
                        defender[n]->GetMotionMaster()->MoveTargetedHome();
                    }
                    uiPhase = 4;
                    break;
                case 4:
                    for (uint8 n = 0; n < RAID_MODE(2, 4); ++n)
                        engineer[n]->SetUInt32Value(UNIT_NPC_EMOTESTATE,
                                EMOTE_STATE_USESTANDING);
                    for (uint8 n = 0; n < 4; ++n)
                        defender[n]->SetUInt32Value(UNIT_NPC_EMOTESTATE,
                                EMOTE_STATE_READY2H);
                    me->MonsterYell(SAY_AGGRO_2, LANG_UNIVERSAL, 0);
                    uiTimer = 16000;
                    uiPhase = 5;
                    break;
                case 5:
                    if (Creature *pRazorscale = me->GetCreature(*me, pInstance->GetData64(TYPE_RAZORSCALE)))
                        pRazorscale->AI()->DoAction(ACTION_EVENT_START);
                    engineer[0]->MonsterYell(SAY_AGGRO_1, LANG_UNIVERSAL, 0);
                    uiPhase = 6;
                    break;
                }
            } else
                uiTimer -= uiDiff;
        }
    };
};

class npc_mole_machine_trigger: public CreatureScript {
public:
    npc_mole_machine_trigger() :
            CreatureScript("npc_mole_machine_trigger") {
    }

    CreatureAI* GetAI(Creature* pCreature) const {
        return new npc_mole_machine_triggerAI(pCreature);
    }

    struct npc_mole_machine_triggerAI: public Scripted_NoMovementAI {
        npc_mole_machine_triggerAI(Creature* pCreature) :
                Scripted_NoMovementAI(pCreature) {
            me->SetFlag(
                    UNIT_FIELD_FLAGS,
                    UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE
                            | UNIT_FLAG_PACIFIED);
            me->SetVisible(false);
        }

        GameObject* MoleMachine;
        uint32 SummonTimer;

        void Reset() {
            MoleMachine = me->SummonGameObject(GOB_MOLE_MACHINE,
                    me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(),
                    float(urand(0, 6)), 0, 0, 0, 0, 300);
            if (MoleMachine)
                MoleMachine->SetGoState(GO_STATE_ACTIVE);
            SummonTimer = 6000;
        }

        void UpdateAI(const uint32 uiDiff) {
            if (!UpdateVictim())
                return;

            if (SummonTimer <= uiDiff) {
                float x = me->GetPositionX();
                float y = me->GetPositionY();
                float z = me->GetPositionZ();

                // One mole can spawn a Dark Rune Watcher with 1-2 Guardians, or a lone Sentinel
                if (!(rand() % 2)) {
                    me->SummonCreature(NPC_DARK_RUNE_WATCHER, x, y, z, 0,
                            TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 3000);
                    uint8 random = urand(1, 2);
                    for (uint8 i = 0; i < random; ++i)
                        me->SummonCreature(NPC_DARK_RUNE_GUARDIAN, x, y, z, 0,
                                TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 3000);
                } else
                    me->SummonCreature(NPC_DARK_RUNE_SENTINEL, x, y, z, 0,
                            TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 3000);

                SummonTimer = 15000;
            } else
                SummonTimer -= uiDiff;
        }

        void JustSummoned(Creature *summon) {
            summon->AI()->DoZoneInCombat();
        }
    };
};

class npc_devouring_flame: public CreatureScript {
public:
    npc_devouring_flame() :
            CreatureScript("npc_devouring_flame") {
    }

    CreatureAI* GetAI(Creature* pCreature) const {
        return new npc_devouring_flameAI(pCreature);
    }

    struct npc_devouring_flameAI: public Scripted_NoMovementAI {
        npc_devouring_flameAI(Creature* pCreature) :
                Scripted_NoMovementAI(pCreature) {
            me->SetFlag(
                    UNIT_FIELD_FLAGS,
                    UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE
                            | UNIT_FLAG_PACIFIED);
            me->SetDisplayId(11686);
        }

        void Reset() {
            DoCast(me, SPELL_FLAME_GROUND);
        }
    };
};

class npc_darkrune_watcher: public CreatureScript {
public:
    npc_darkrune_watcher() :
            CreatureScript("npc_darkrune_watcher") {
    }

    CreatureAI* GetAI(Creature* pCreature) const {
        return new npc_darkrune_watcherAI(pCreature);
    }

    struct npc_darkrune_watcherAI: public ScriptedAI {
        npc_darkrune_watcherAI(Creature *pCreature) :
                ScriptedAI(pCreature) {
            pInstance = pCreature->GetInstanceScript();
        }

        InstanceScript *pInstance;

        uint32 ChainTimer;
        uint32 LightTimer;

        void Reset() {
            ChainTimer = urand(10000, 15000);
            LightTimer = urand(1000, 3000);
        }

        void UpdateAI(const uint32 uiDiff) {
            if (!UpdateVictim())
                return;

            if (ChainTimer <= uiDiff) {
                DoCastVictim(SPELL_CHAIN_LIGHTNING);
                ChainTimer = urand(10000, 15000);
            } else
                ChainTimer -= uiDiff;

            if (LightTimer <= uiDiff) {
                DoCastVictim(SPELL_LIGHTNING_BOLT);
                LightTimer = urand(5000, 7000);
            } else
                LightTimer -= uiDiff;

            DoMeleeAttackIfReady();
        }
    };
};

class npc_darkrune_guardian: public CreatureScript {
public:
    npc_darkrune_guardian() :
            CreatureScript("npc_darkrune_guardian") {
    }

    CreatureAI* GetAI(Creature* pCreature) const {
        return new npc_darkrune_guardianAI(pCreature);
    }

    struct npc_darkrune_guardianAI: public ScriptedAI {
        npc_darkrune_guardianAI(Creature *pCreature) :
                ScriptedAI(pCreature) {
            pInstance = pCreature->GetInstanceScript();
        }

        InstanceScript *pInstance;

        uint32 StormTimer;

        void Reset() {
            StormTimer = urand(3000, 6000);
        }

        void UpdateAI(const uint32 uiDiff) {
            if (!UpdateVictim())
                return;

            if (StormTimer <= uiDiff) {
                DoCastVictim(SPELL_STORMSTRIKE);
                StormTimer = urand(4000, 8000);
            } else
                StormTimer -= uiDiff;

            DoMeleeAttackIfReady();
        }
    };
};

class npc_darkrune_sentinel: public CreatureScript {
public:
    npc_darkrune_sentinel() :
            CreatureScript("npc_darkrune_sentinel") {
    }

    CreatureAI* GetAI(Creature* pCreature) const {
        return new npc_darkrune_sentinelAI(pCreature);
    }

    struct npc_darkrune_sentinelAI: public ScriptedAI {
        npc_darkrune_sentinelAI(Creature *pCreature) :
                ScriptedAI(pCreature) {
            pInstance = pCreature->GetInstanceScript();
        }

        InstanceScript *pInstance;

        uint32 HeroicTimer;
        uint32 WhirlTimer;
        uint32 ShoutTimer;

        void Reset() {
            HeroicTimer = urand(4000, 8000);
            WhirlTimer = urand(20000, 25000);
            ShoutTimer = urand(15000, 30000);
        }

        void UpdateAI(const uint32 uiDiff) {
            if (!UpdateVictim())
                return;

            if (HeroicTimer <= uiDiff) {
                DoCastVictim(SPELL_HEROIC_STRIKE);
                HeroicTimer = urand(4000, 6000);
            } else
                HeroicTimer -= uiDiff;

            if (WhirlTimer <= uiDiff) {
                DoCastVictim(SPELL_WHIRLWIND);
                WhirlTimer = urand(20000, 25000);
            } else
                WhirlTimer -= uiDiff;

            if (ShoutTimer <= uiDiff) {
                DoCast(me, SPELL_BATTLE_SHOUT);
                ShoutTimer = urand(30000, 40000);
            } else
                ShoutTimer -= uiDiff;

            DoMeleeAttackIfReady();
        }
    };
};

class achievement_quick_shave : public AchievementCriteriaScript
{
    public:
        achievement_quick_shave() : AchievementCriteriaScript("achievement_quick_shave") { }

        bool OnCheck(Player* /*source*/, Unit* target)
        {
           if (target)
                if (Creature* razorscale = target->ToCreature())
                    if (razorscale->AI()->GetData(DATA_QUICK_SHAVE))
                        return true;

            return false;
        }
};

void AddSC_boss_razorscale() {
    new boss_razorscale();
    new npc_expedition_commander();
    new npc_mole_machine_trigger();
    new npc_devouring_flame();
    new npc_darkrune_watcher();
    new npc_darkrune_guardian();
    new npc_darkrune_sentinel();
	new achievement_quick_shave();
}
